package com.example.springevent.ivd.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.springevent.event.bo.IvdAddedEventBO;
import com.example.springevent.event.bo.IvdRemovedEventBO;
import com.example.springevent.event.event.IvdAddedEvent;
import com.example.springevent.event.listener.IvdRemovedEventPoListener;
import com.example.springevent.ivd.domain.InvoiceVerifyDetail;
import com.example.springevent.ivd.service.IvdServiceI;
import com.example.springevent.mockdata.IvdSampleData;

@Service
public class IvdServiceImpl implements IvdServiceI {
	private static final Logger log = LoggerFactory.getLogger(IvdServiceImpl.class);
	@Autowired
	private ApplicationContext context;
	@Autowired
	private ApplicationEventPublisher publisher;
	@Autowired
	private ApplicationEventMulticaster multicaster;

	@Override
	public void addIvd(InvoiceVerifyDetail ivd) {
		log.info("addIvd in IvdServiceImpl begin");
		// 业务逻辑：add ivd
		IvdSampleData.add(ivd);
		
		// publish event
		IvdAddedEventBO eventBO = new IvdAddedEventBO();
		BeanUtils.copyProperties(ivd, eventBO);
		publishApplicationEvent(new IvdAddedEvent(eventBO));
		
		log.info("addIvd in IvdServiceImpl end");
	}
	
	@Override
	@Transactional
	public void addIvdInTran(InvoiceVerifyDetail ivd) {
		log.info("addIvdInTran in IvdServiceImpl begin。Thread={}", Thread.currentThread().getName());
		// add ivd
		IvdSampleData.add(ivd);
		
		// publish event
		IvdAddedEventBO eventBO = new IvdAddedEventBO();
		BeanUtils.copyProperties(ivd, eventBO);
		publishApplicationEvent(new IvdAddedEvent(eventBO));
		
		log.info("addIvdInTran in IvdServiceImpl end。Thread={}", Thread.currentThread().getName());
	}

	/**
	 * 	事件定义：
	 * @see com.example.springevent.event.event.IvdAddedEvent extends ApplicationEvent
	 * 
	 * 	事件监听：implements ApplicationListener接口方式定义事件监听 
	 * @see com.example.springevent.event.listener.IvdAddedEventInvoiceListener implements ApplicationListener<IvdAddedEvent>
	 * 	事件监听：@EventListener方式定义事件监听 
	 * @see com.example.springevent.event.methodlistener.IvdEventListenerInvoiceHandler#handleIvdAddedEvent(IvdAddedEvent event)
	 * 	事件监听：@TransactionalEventListener方式定义事件监听 
	 * @see com.example.springevent.event.methodlistener.IvdEventListenerInvoiceHandler#handleIvdAddedEventInTran(IvdAddedEvent event)
	 * 	事件监听：@TransactionalEventListener方式定义事件监听 
	 * @see com.example.springevent.event.methodlistener.IvdEventListenerInvoiceHandler#handleIvdAddedEventInTranFallBackTrue(IvdAddedEvent event)
	 * 
	 * 	发布事件：
	 * @see context.publishEvent(IvdAddedEvent event);
	 * 
	 * @param eventBO
	 */
	private void publishApplicationEvent(IvdAddedEvent event) {
		log.info("发布自定义事件");
//		log.info("通过ApplicationContext发布事件");
		context.publishEvent(event);
//		log.info("通过ApplicationEventPublisher发布事件");
//		publisher.publishEvent(event);
//		log.info("通过ApplicationEventMulticaster发布事件");
//		multicaster.multicastEvent(event);
	}

	@Override
	public void removeIvd(InvoiceVerifyDetail ivd) {
		log.info("removeIvd");
		// remove ivd
		IvdSampleData.remove(ivd);
		// publish event
		IvdRemovedEventBO eventBO = new IvdRemovedEventBO();
		BeanUtils.copyProperties(ivd, eventBO);
		publishPayloadApplicationEvent(eventBO);
	}
	
	/**
	 * 	事件定义：
	 * @see org.springframework.context.PayloadApplicationEvent<T>
	 * @see com.example.springevent.event.bo.IvdRemovedEventBO
	 * 
	 * 	事件监听：implements ApplicationListener接口方式定义事件监听 
	 * @see IvdRemovedEventPoListener implements ApplicationListener<PayloadApplicationEvent<IvdRemovedEventBO>>
	 * @see com.example.springevent.event.listener.IvdRemovedEventPoListener#onApplicationEvent
	 * 	事件监听：@EventListener方式定义事件监听 
	 * @see com.example.springevent.event.methodlistener.IvdEventListenerPoHandler#handleIvdRemovedEvent(IvdRemovedEventBO ivd)
	 * 	事件监听：@TransactionalEventListener方式定义事件监听 
	 * @see com.example.springevent.event.methodlistener.IvdEventListenerPoHandler#handleIvdRemovedEventInTran(IvdRemovedEventBO ivd)
	 * 
	 * 	发布事件：
	 * @see context.publishEvent(IvdRemovedEventBO eventBO);
	 * 
	 * @param eventBO
	 */
	private void publishPayloadApplicationEvent(IvdRemovedEventBO eventBO) {
		log.info("发布PayloadApplicationEvent事件");
		context.publishEvent(eventBO);
	}

}
